package com.one.rope.mvp.web.service.user;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.one.rope.mvp.basecore.bean.ResponseMessage;
import com.one.rope.mvp.basecore.bean.UserBusinessMessage;
import com.one.rope.mvp.basecore.third.wx.miniprogram.MiniprogramAuthoReqVO;
import com.one.rope.mvp.basecore.third.wx.miniprogram.MiniprogramAuthoResVO;
import com.one.rope.mvp.basecore.third.wx.miniprogram.WxMiniprogramUtil;
import com.one.rope.mvp.basecore.util.MyBeanUtils;
import com.one.rope.mvp.basecore.util.StringUtils;
import com.one.rope.mvp.web.business.dao.CompanyMapper;
import com.one.rope.mvp.web.business.dao.CompanyMemberMapper;
import com.one.rope.mvp.web.business.dao.MemberInfoMapper;
import com.one.rope.mvp.web.business.dao.MemberSubscribeRecordMapper;
import com.one.rope.mvp.web.business.entity.Company;
import com.one.rope.mvp.web.business.entity.CompanyMember;
import com.one.rope.mvp.web.business.entity.MemberInfo;
import com.one.rope.mvp.web.business.entity.MemberSubscribeRecord;
import com.one.rope.mvp.web.common.auth.TokenManager;
import com.one.rope.mvp.web.common.auth.UserInfo;
import com.one.rope.mvp.web.common.auth.UserLoginUtil;
import com.one.rope.mvp.basecore.bean.BusinessMessage;
import com.one.rope.mvp.basecore.bean.ResponseObject;
import com.one.rope.mvp.web.common.dto.user.auth.UserLoginDTO;
import com.one.rope.mvp.web.common.dto.user.auth.UserLoginVO;
import com.one.rope.mvp.web.common.dto.user.userinfo.GetUserInfoVO;
import com.one.rope.mvp.web.common.dto.user.userinfo.RegisterBUserInfoDTO;
import com.one.rope.mvp.web.common.dto.user.userinfo.RegisterCUserInfoDTO;
import com.one.rope.mvp.web.common.dto.user.userinfo.SaveUserInfoDTO;
import com.one.rope.mvp.web.common.enums.UserTypeEnum;
import com.one.rope.mvp.web.common.enums.VerifyCodeTypeEnum;
import com.one.rope.mvp.basecore.exception.BusinessDataException;
import com.one.rope.mvp.web.common.dto.user.userinfo.GetVerifyCodeDTO;
import com.one.rope.mvp.web.common.redis.AuthRedisOperator;
import com.one.rope.mvp.web.common.util.VerifyCodeUtl;
import com.one.rope.mvp.web.config.CommonConfig;
import com.one.rope.mvp.web.config.GlobalConfig;
import com.one.rope.mvp.web.service.sms.AliyunSmsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 * 小程序用户信息接口服务
 * <p>
 *
 * @author ： Weijian.Liu
 * @date ： 2020/3/9 16:12
 */
@Service
@Slf4j
public class UserService {

  @Autowired
  CommonConfig commonConfig;

  @Autowired
  MemberInfoMapper memberInfoMapper;

  @Autowired
  TokenManager tokenManager;

  @Autowired
  CompanyMapper companyMapper;

  @Autowired
  AliyunSmsService aliyunSmsService;

  @Autowired
  CompanyMemberMapper companyMemberMapper;

  @Autowired
  MemberSubscribeRecordMapper memberSubscribeRecordMapper;

  /**
   * 用户登录
   */
  @Transactional(rollbackFor = Exception.class)
  public ResponseObject<UserLoginVO> userLogin(UserLoginDTO requestDTO) {
    UserLoginVO resVO = new UserLoginVO();
    // 获取openId
    MiniprogramAuthoReqVO authoReqVO = new MiniprogramAuthoReqVO();
    authoReqVO.setCode(requestDTO.getCode());
    authoReqVO.setAppId(commonConfig.getWxMiniProgramAppId());
    authoReqVO.setAppSecret(commonConfig.getWxMiniProgramAppSecret());
    authoReqVO.setCode2SessionUrl(commonConfig.getWxMiniProgramCode2SessionUrl());
    MiniprogramAuthoResVO authoResVO = WxMiniprogramUtil.wxMiniprogramLogin(authoReqVO);
    if(StringUtils.isNullOrEmpty(authoResVO.getOpenid())){
      throw new BusinessDataException(UserBusinessMessage.USER_AUTHO_FAILURE);
    }
    String openId = authoResVO.getOpenid();
    String wxUnionId = authoResVO.getUnionid();
//    String wxUnionId = "o6AnSv5m2AKMY6w6zOamjyzzOsxQ";
//    String openId = "oV9bU5KQyjrb5-E2JrN7P9vroDr4";

    log.info("get wxUnionId: {}", wxUnionId);
    log.info("get openId: {}", openId);
    // 查询用户是否存在，如果不存在则注册用户
    QueryWrapper<MemberInfo> queryWrapper = new QueryWrapper<MemberInfo>();
    queryWrapper.eq("wx_open_id", openId);

    UserInfo userInfo = new UserInfo();
    MemberInfo dbMemberInfo = memberInfoMapper.selectOne(queryWrapper);
    if(null == dbMemberInfo){
      // 注册用户
      MemberInfo memberInfo = new MemberInfo();
      memberInfo.setWxOpenId(openId);
      memberInfo.setWxUnionId(wxUnionId);
      memberInfo.setUserType(requestDTO.getUserType());
      memberInfoMapper.insert(memberInfo);
      dbMemberInfo = memberInfo;
      if(!StringUtils.isNullOrEmpty(wxUnionId)){
        updateOfficeOpenId(dbMemberInfo);
      }
    }else{
      if(!StringUtils.isNullOrEmpty(wxUnionId) && StringUtils.isNullOrEmpty(dbMemberInfo.getWxUnionId())){
        dbMemberInfo.setWxUnionId(wxUnionId);
        updateOfficeOpenId(dbMemberInfo);
      }
      if(dbMemberInfo.getUserType() == UserTypeEnum.B.getCode()){
        Company company = new Company();
        if(null != dbMemberInfo.getCompanyId()){
          company = companyMapper.selectById(dbMemberInfo.getCompanyId());
        }
        userInfo.setCompany(company);
      }
    }

    // 生成token
    UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(openId, GlobalConfig.USER_TOKEN_SIMULATE_PWD);
    Subject subject = SecurityUtils.getSubject();
    subject.login(usernamePasswordToken);
    userInfo.setMemberInfo(dbMemberInfo);
    userInfo.setUsernamePasswordToken(usernamePasswordToken);
    String token = tokenManager.saveUserToken(userInfo);

    resVO.setToken(token);
    return new ResponseObject<>(resVO);
  }

  /**
   * 获取用户信息
   * @return
   */
  public ResponseObject<GetUserInfoVO> getUserInfo() {
    UserInfo userInfo = UserLoginUtil.getUserInfo();
    MemberInfo memberInfo = memberInfoMapper.selectById(userInfo.getMemberInfo().getId());
    GetUserInfoVO resultVO = new GetUserInfoVO();
    MyBeanUtils.copyPropertiesIgnoreNull(memberInfo, resultVO);
    if(memberInfo.getUserType() == UserTypeEnum.B.getCode() && memberInfo.getIsFillInfo() == 1){
      Company company = companyMapper.selectOne(new QueryWrapper<Company>().eq("id", memberInfo.getCompanyId()));
      resultVO.setCompanyName(company.getName());
    }

    // 临时处理，如果用户还没注册每次都清理缓存
    if(memberInfo.getIsFillInfo() == 0){
      tokenManager.deleteUserToken(userInfo.getToken());
      tokenManager.deleteUserId(String.valueOf(userInfo.getMemberInfo().getId()));
    }
    return new ResponseObject<>(resultVO);
  }

  /**
   * 获取验证码
   * @param requestDTO
   * @return
   */
  public ResponseObject getVerifyCode(GetVerifyCodeDTO requestDTO) {
    String code = VerifyCodeUtl.getVerifyCode();
    if(commonConfig.getEnableSendSms() == 0){
      ResponseObject response = aliyunSmsService.sendCodeMessage(requestDTO.getMobile(), code);
      if(!response.success()){
        return response;
      }
    }
    try {
      // 缓存验证码
      AuthRedisOperator.saveVerifyCode(code, requestDTO.getMobile(), requestDTO.getType());
    }catch (Exception e){
      throw new BusinessDataException(ResponseMessage.systemError(e));
    }
    return ResponseObject.successObject();
  }

  /**
   * C端用户注册
   * @param requestDTO
   * @return
   */
  public ResponseObject registerC(RegisterCUserInfoDTO requestDTO) throws Exception{
    UserInfo userInfo = UserLoginUtil.getUserInfo();
    String cacheCode = AuthRedisOperator.getVerifyCode(requestDTO.getMobile(), VerifyCodeTypeEnum.C_REGISTER.getCode());
    // 数据校验
    checkRegisterData(requestDTO.getMobile(), requestDTO.getCode(), cacheCode);

    // 更新用户信息
    MemberInfo memberInfo = new MemberInfo();
    MyBeanUtils.copyPropertiesIgnoreNull(requestDTO, memberInfo);
    memberInfo.setId(userInfo.getMemberInfo().getId());
    memberInfo.setIsFillInfo(1);
    memberInfoMapper.updateById(memberInfo);

    //弥补措施，更新公众号openId
    MemberInfo dbMember = memberInfoMapper.selectById(userInfo.getMemberInfo().getId());
    if(null != dbMember && StringUtils.isNullOrEmpty(dbMember.getWxUnionId())){
      updateOfficeOpenId(dbMember);
    }

    // 更新缓存
    userInfo.setMemberInfo(memberInfo);
    UserLoginUtil.updateUserLoginInfo(userInfo.getToken(), userInfo);
    return ResponseObject.successObject();
  }

  /**
   * B端用户注册
   * @param requestDTO
   * @return
   */
  @Transactional(rollbackFor = Exception.class)
  public ResponseObject registerB(RegisterBUserInfoDTO requestDTO) throws Exception{
    UserInfo userInfo = UserLoginUtil.getUserInfo();
    String cacheCode = AuthRedisOperator.getVerifyCode(requestDTO.getMobile(), VerifyCodeTypeEnum.B_REGISTER.getCode());
    // 数据校验
    checkRegisterData(requestDTO.getMobile(), requestDTO.getCode(), cacheCode);

    // B端用户，添加企业主体信息
    Company company = new Company();
    company.setName(requestDTO.getCompanyName());
    company.setCompanyValue(requestDTO.getCompanyValue());
    company.setValueCurrency(requestDTO.getValueCurrency());
    companyMapper.insert(company);

    // 添加企业核心团队成员
    CompanyMember companyMember = new CompanyMember();
    companyMember.setMemberId(userInfo.getMemberInfo().getId());
    companyMember.setCompanyId(company.getId());
    companyMember.setName(requestDTO.getName());
    companyMember.setSex(requestDTO.getSex());
    companyMember.setBirthday(requestDTO.getBirthday());
    companyMember.setPostName(requestDTO.getCompanyPost());
    companyMemberMapper.insert(companyMember);

    // 更新用户信息
    MemberInfo memberInfo = new MemberInfo();
    MyBeanUtils.copyPropertiesIgnoreNull(requestDTO, memberInfo);
    memberInfo.setId(userInfo.getMemberInfo().getId());
    memberInfo.setIsFillInfo(1);
    memberInfo.setCompanyId(company.getId());
    memberInfoMapper.updateById(memberInfo);

    //弥补措施，更新公众号openId
    MemberInfo dbMember = memberInfoMapper.selectById(userInfo.getMemberInfo().getId());
    if(null != dbMember && StringUtils.isNullOrEmpty(dbMember.getWxUnionId())){
      updateOfficeOpenId(dbMember);
    }

    // 更新缓存
    userInfo.setMemberInfo(memberInfo);
    userInfo.setCompany(company);
    UserLoginUtil.updateUserLoginInfo(userInfo.getToken(), userInfo);

    return ResponseObject.successObject();
  }

  /**
   * 用户注册数据校验
   * @param mobile
   * @param code
   * @param cacheCode
   */
  private void checkRegisterData(String mobile, String code, String cacheCode){
    // 校验验证码是否过期
    if(StringUtils.isNullOrEmpty(cacheCode)){
      throw new BusinessDataException(BusinessMessage.VERIFY_CODE_EXPIRED);
    }
    // 校验验证码是否正确，如果没有开启短信不校验
    if(commonConfig.getEnableSendSms() == 0){
      if(!code.equals(cacheCode)){
        throw new BusinessDataException(BusinessMessage.VERIFY_CODE_ERROR);
      }
    }
    // 校验手机号是否被使用
    MemberInfo dbMemberInfo = memberInfoMapper.selectOne(
        new QueryWrapper<MemberInfo>().eq("mobile", mobile));
    if(null != dbMemberInfo){
      throw new BusinessDataException(BusinessMessage.MOBILE_IS_USERD);
    }
  }

  /**
   * 更新公众号openId
   */
  public void updateOfficeOpenId(MemberInfo member){
    if(!StringUtils.isNullOrEmpty(member.getWxUnionId())){
      MemberInfo memberInfo = new MemberInfo();
      memberInfo.setId(member.getId());
      memberInfo.setWxUnionId(member.getWxUnionId());
      MemberSubscribeRecord dbSubscribeRecord = memberSubscribeRecordMapper.selectOne(
              new QueryWrapper<MemberSubscribeRecord>().eq("wx_union_id", member.getWxUnionId())
      );
      if(null != dbSubscribeRecord){
        memberInfo.setWxOfficialOpenId(dbSubscribeRecord.getWxOfficialOpenId());
      }
      memberInfoMapper.updateById(memberInfo);
    }
  }

  /**
   * 保存用户信息
   * @param requestDTO
   * @return
   */
  @Transactional(rollbackFor = Exception.class)
  public ResponseObject saveUserInfo(SaveUserInfoDTO requestDTO) {
    UserInfo userInfo = UserLoginUtil.getUserInfo();
    MemberInfo memberInfo = new MemberInfo();
    memberInfo.setId(userInfo.getMemberInfo().getId());
    memberInfo.setName(requestDTO.getName());
    memberInfo.setSex(requestDTO.getSex());
    memberInfoMapper.updateById(memberInfo);
    if(userInfo.getMemberInfo().getUserType() == UserTypeEnum.B.getCode()){
      // B端用户还需要更新企业成员信息
      CompanyMember companyMember = new CompanyMember();
      companyMember.setName(requestDTO.getName());
      companyMember.setSex(requestDTO.getSex());
      companyMemberMapper.update(companyMember, new QueryWrapper<CompanyMember>()
         .eq("member_id", userInfo.getMemberInfo().getId())
      );
    }
    return ResponseObject.successObject();
  }

  /**
   * 清除当前用户信息
   * @return
   */
  @Transactional(rollbackFor = Exception.class)
  public ResponseObject deleteUser() {
    UserInfo userInfo = UserLoginUtil.getUserInfo();
    memberInfoMapper.deleteById(userInfo.getMemberInfo().getId());
    if(null != userInfo.getCompany()){
      companyMapper.deleteById(userInfo.getCompany().getId());
    }
    // 清除缓存
    tokenManager.deleteUserToken(userInfo.getToken());
    tokenManager.deleteUserId(String.valueOf(userInfo.getMemberInfo().getId()));
    return ResponseObject.successObject();
  }
}
